/**
 * 
 */
package com.vision.sales.sv.util;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateTemplate;

import com.vision.core.cm.util.DateUtils;
import com.vision.core.sv.db.mgr.ISimpleCriteria;
import com.vision.core.sv.db.mgr.SimpleCriteria;
import com.vision.core.sv.util.CollectionUtils;
import com.vision.sales.cl.ui.component.TransactionLoadConfig;
import com.vision.sales.cm.data.TransactionType;
import com.vision.sales.cm.db.data.TransactionEntry;

/**
 * @author Mark
 *
 */
public class TransactionHelper {
	
	public static ISimpleCriteria previousTransactionEntries(TransactionLoadConfig config) {
		ISimpleCriteria crit = SimpleCriteria.forClass(TransactionEntry.class);
		crit.lt("date", config.getStart());
		
		if (!CollectionUtils.isNullOrEmpty(config.getCompanies()))
			crit.in("company.id", CollectionUtils.listFrom(config.getCompanies(), "getId"));
		
		if (!CollectionUtils.isNullOrEmpty(config.getCustomers()))
			crit.in("customer.id", CollectionUtils.listFrom(config.getCustomers(), "getId"));
		
		if (!CollectionUtils.isNullOrEmpty(config.getTypes()))
			crit.in("type", config.getTypes());
		
		crit.asc("date", "customer.id", "type");
		
		return crit;
	}
	
	public static ISimpleCriteria transactionEntry(TransactionLoadConfig config) {
		ISimpleCriteria crit = SimpleCriteria.forClass(TransactionEntry.class);
		crit.between("date", config.getStart(), config.getEnd());
		
		if (!CollectionUtils.isNullOrEmpty(config.getCompanies()))
			crit.in("company.id", CollectionUtils.listFrom(config.getCompanies(), "getId"));
		
		if (!CollectionUtils.isNullOrEmpty(config.getCustomers()))
			crit.in("customer.id", CollectionUtils.listFrom(config.getCustomers(), "getId"));
		
		if (!CollectionUtils.isNullOrEmpty(config.getTypes()))
			crit.in("type", config.getTypes());
		
		if (!config.isIncludeZeros())
			crit.or(Restrictions.gt("debit", 0d), Restrictions.gt("credit", 0d));
		
		crit.asc("date", "customer.id", "type");
		
		return crit;
	}
	
	public static ISimpleCriteria transactionEntry(List<Long> companies, List<Long> customers, List<TransactionType> types) {
		ISimpleCriteria crit = SimpleCriteria.forClass(TransactionEntry.class);
		
		if (!CollectionUtils.isNullOrEmpty(companies))
			crit.in("company.id", companies);
		
		if (!CollectionUtils.isNullOrEmpty(customers))
			crit.in("customer.id", customers);
		
		if (!CollectionUtils.isNullOrEmpty(types))
			crit.in("type", types);
		
		return crit;
	}
	
	public static List<TransactionEntry> getStartingBalances(TransactionLoadConfig config, List<TransactionEntry> entries) {
		Map<Long, TransactionEntry> map = new HashMap<Long, TransactionEntry>();
		
		for (TransactionEntry entry : entries) {
			// Get the "Starting Balance" entry for the customer
			TransactionEntry startingBalance = map.get(entry.getCustomer().getId());
			if (startingBalance == null) {
				startingBalance = new TransactionEntry();
				startingBalance.setCompany(entry.getCompany()); // Not really needed
				startingBalance.setCustomer(entry.getCustomer());
				startingBalance.setDate(new Date(config.getStart().getTime() - DateUtils.ONE_DAY_IN_MILLIS)); // Less one day
				startingBalance.setDebit(0d);
				startingBalance.setCredit(0d);
				startingBalance.setType(TransactionType.STARTING_BALANCE);
				startingBalance.setTransactionRefNo(""); // Not really needed, so we just set to empty
				map.put(entry.getCustomer().getId(), startingBalance);
			}
			
			startingBalance.setBalance(startingBalance.getBalance() + entry.getDebit() - entry.getCredit());
		}
		
		return new ArrayList<TransactionEntry>(map.values());
	}
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	public static ISimpleCriteria createCriteria(Class<?> clazz, TransactionLoadConfig config) {
		ISimpleCriteria crit = SimpleCriteria.forClass(clazz);
		
		// FIXME What if the user is not assigned to any company?
		if (!CollectionUtils.isNullOrEmpty(config.getCompanies())) {
			List<Long> ids = CollectionUtils.listFrom(config.getCompanies(), "getId");
			crit.in("company.id", ids);
		}
		
		if (config.getStart() != null && config.getEnd() != null)
			crit.between("date", config.getStart(), config.getEnd());
		
		if (!CollectionUtils.isNullOrEmpty(config.getStatuses()))
			crit.in("status", config.getStatuses());
		
		if (!CollectionUtils.isNullOrEmpty(config.getProducts())) {
			List<Long> ids = CollectionUtils.listFrom(config.getProducts(), "getId");
			crit.in("product.id", ids);
		}
		
		if (!CollectionUtils.isNullOrEmpty(config.getSalesmen())) {
			List<Long> ids = CollectionUtils.listFrom(config.getSalesmen(), "getId");
			crit.in("salesman.id", ids);
		}
		
		if (!CollectionUtils.isNullOrEmpty(config.getCustomers())) {
			List<Long> ids = CollectionUtils.listFrom(config.getCustomers(), "getId");
			crit.in("customer.id", ids);
		}
		
		crit.desc("date", "status");
		
		return crit;
	}
	
	public static ISimpleCriteria createCountCriteria(Class<?> clazz, TransactionLoadConfig config) {
		ISimpleCriteria crit = SimpleCriteria.forClass(clazz);
		
		if (!CollectionUtils.isNullOrEmpty(config.getCompanies())) {
			List<Long> ids = CollectionUtils.listFrom(config.getCompanies(), "getId");
			crit.in("company.id", ids);
		}
		
		if (config.getStart() != null && config.getEnd() != null)
			crit.between("date", config.getStart(), config.getEnd());
		
		if (!CollectionUtils.isNullOrEmpty(config.getStatuses()))
			crit.in("status", config.getStatuses());
		
		if (!CollectionUtils.isNullOrEmpty(config.getProducts())) {
			List<Long> ids = CollectionUtils.listFrom(config.getProducts(), "getId");
			crit.in("product.id", ids);
		}
		
		if (!CollectionUtils.isNullOrEmpty(config.getSalesmen())) {
			List<Long> ids = CollectionUtils.listFrom(config.getSalesmen(), "getId");
			crit.in("salesman.id", ids);
		}
		
		if (!CollectionUtils.isNullOrEmpty(config.getCustomers())) {
			List<Long> ids = CollectionUtils.listFrom(config.getCustomers(), "getId");
			crit.in("customer.id", ids);
		}
		
		crit.count();
		
		return crit;
	}
	
	public static List<?> getList(Class<?> clazz, TransactionLoadConfig config, HibernateTemplate template) {
		ISimpleCriteria crit = createCriteria(clazz, config);
		return getList(crit, config, template);
	}
	
	public static List<?> getList(ISimpleCriteria criteria, TransactionLoadConfig config, HibernateTemplate template) {
		return template.findByCriteria(criteria.getDetached(), config.getOffset(), config.getLimit());
	}
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	

}
